#ifndef UTILITY_H
#define UTILITY_H

#include "ObjHandler.h"
#include "Smoother.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <glut.h>
#include <glui.h>

static GLint    ImageWidth=500;
static GLint    ImageHeight=500;


GLuint *displayListID;


float obj_rot[16];

GLfloat light_position[4]={0.0, 0.0, 3.0, 1.0};

GLfloat eye_position[4]={0,0,-3,1};



GLUI *glui;

Smoother* engine;

void InitModel();
void InitGL();
void drawModel();
void InitDisplayList();

void InitGL()
{
	glLightfv(GL_LIGHT0, GL_POSITION, light_position);
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	glDepthFunc(GL_LESS);
	glEnable(GL_DEPTH_TEST);

	glViewport(0, 0, (GLsizei) ImageWidth, (GLsizei) ImageHeight);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0f,(GLfloat) ImageWidth / (GLfloat)ImageHeight , 0.5f, -1000.0f);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void InitModel()
{
	displayListID = (GLuint*)malloc(sizeof(GLuint));
	displayListID[0] = glGenLists(1);

	OBJHandler mesh;
	mesh.LoadOBJascii("test1.obj");

	engine=new ImplicitSmoother(10.0, 1);

	for (int i=0;i<mesh.numVerts;i++)
	{
		Vertex* v=new Vertex();
		Vertex* nV=new Vertex();

		v->index=i;
		nV->index=i;
		v->position=vector3(mesh.verts[i].x,mesh.verts[i].y,mesh.verts[i].z);
		v->normal=vector3(mesh.normal[i].x,mesh.normal[i].y,mesh.normal[i].z);

		engine->vertices->push_back(v);	
		engine->newVertices->push_back(nV);
	}

	for (int i=0;i<mesh.numTris;i++)
	{
		Triangle* tri=new Triangle();
		
		tri->v1=mesh.tris[i].v1;
		tri->v2=mesh.tris[i].v2;
		tri->v3=mesh.tris[i].v3;

		engine->triangles.push_back(tri);

		engine->vertices->at(tri->v1)->neighbour.push_back(tri);
		engine->vertices->at(tri->v2)->neighbour.push_back(tri);
		engine->vertices->at(tri->v3)->neighbour.push_back(tri);

		engine->newVertices->at(tri->v1)->neighbour.push_back(tri);
		engine->newVertices->at(tri->v2)->neighbour.push_back(tri);
		engine->newVertices->at(tri->v3)->neighbour.push_back(tri);
	}

	engine->InitLaplacian();

	engine->ApplySmoothing(1);

	InitDisplayList();	
	
}

void drawModel()
{
	glCallList(displayListID[0]);
}

void InitDisplayList()
{
	glNewList(displayListID[0], GL_COMPILE);
	glBegin(GL_TRIANGLES);

	for (int i=0;i<engine->triangles.size();i++)
	{
		Triangle* tri=engine->triangles.at(i);

		Vertex *v1, *v2, *v3;

		v1=engine->vertices->at(tri->v1);
		v2=engine->vertices->at(tri->v2);
		v3=engine->vertices->at(tri->v3);

		glNormal3f(v1->normal.x,v1->normal.y,v1->normal.z);
		glVertex3f(v1->position.x,v1->position.y,v1->position.z);

		glNormal3f(v2->normal.x,v2->normal.y,v2->normal.z);
		glVertex3f(v2->position.x,v2->position.y,v2->position.z);

		glNormal3f(v3->normal.x,v3->normal.y,v3->normal.z);
		glVertex3f(v3->position.x,v3->position.y,v3->position.z);
	}
	glEnd();
	glEndList();
}


#endif